package com.cinc.ebc.mm.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
import com.cinc.ebc.mm.entity.MmMaterialStock;
import com.cinc.ebc.mm.entity.MmStockInOut;
import com.cinc.ebc.mm.entity.MmStockInOutDetail;
import com.cinc.ebc.mm.mapper.MmMaterialStockMapper;
import com.cinc.ebc.mm.model.MmMaterialStockAllocateModel;
import com.cinc.ebc.mm.model.MmRptMaterialStockWarehouseStatModel;
import com.cinc.ebc.mm.model.MmRptMaterialStockWarehouseStatTotalModel;
import com.cinc.ebc.mm.service.IMmMaterialStockService;
import com.cinc.ebc.mm.vo.MmRptMaterialStockStatPage;
import com.cinc.mdm.constant.MdmConstant;
import com.cinc.mdm.modules.movementType.entity.MdmMovementType;
import com.cinc.mdm.modules.movementType.mapper.MdmMovementTypeMapper;
import org.apache.commons.lang3.StringUtils;
import org.jeecg.common.util.oConvertUtils;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Arrays;
import java.util.List;

/**
 * @Description: 库存量
 * @Author: jeecg-boot
 * @Date: 2022-04-10
 * @Version: V1.0
 */
@Service
public class MmMaterialStockServiceImpl extends ServiceImpl<MmMaterialStockMapper, MmMaterialStock> implements IMmMaterialStockService {

    @Autowired
    private MmMaterialStockMapper mmMaterialStockMapper;

    @Autowired
    private MdmMovementTypeMapper mdmMovementTypeMapper;

    @Override
    public boolean saveMaterialStock(MmMaterialStock entity) throws Exception {
        if (StringUtils.isBlank(entity.getMaterialId())) {
            throw new RuntimeException("物料不能为空");
        }
        if (StringUtils.isBlank(entity.getWarehouseId())) {
            throw new RuntimeException("库房不能为空");
        }

        return SqlHelper.retBool(this.getBaseMapper().insert(entity));
    }

    /**
     * 根据出入库单据更新库存
     *
     * @param mmStockInOut
     * @param mmStockInOutDetailList
     * @param isAllocate
     * @return boolean
     * @throws Exception
     */
    @Override
    @Transactional
    public boolean updateByStockInOutDetail(MmStockInOut mmStockInOut, List<MmStockInOutDetail> mmStockInOutDetailList, boolean isAllocate) throws Exception {
        if (mmStockInOut == null || oConvertUtils.listIsEmpty(mmStockInOutDetailList)) {
            throw new RuntimeException("单据为空，库存更新失败");
        }
        MdmMovementType mdmMovementType = mdmMovementTypeMapper.selectById(mmStockInOut.getMoveId());
        if (mdmMovementType == null) {
            throw new RuntimeException("移动类型设置错误,库存更新失败");
        }
        //
        String projectId = StringUtils.isBlank(mmStockInOut.getProjectId()) ? "" : mmStockInOut.getProjectId();
        for (MmStockInOutDetail stockInOutDetail : mmStockInOutDetailList) {
            String materialId = StringUtils.isBlank(stockInOutDetail.getMaterialId()) ? "" : stockInOutDetail.getMaterialId();
            if (StringUtils.isBlank(materialId)) {
                throw new RuntimeException("物料为空，库存更新失败");
            }
            String warehouseId = StringUtils.isBlank(stockInOutDetail.getWarehouseId()) ? "" : stockInOutDetail.getWarehouseId();
            if (StringUtils.isBlank(warehouseId)) {
                throw new RuntimeException("库房为空，库存更新失败");
            }
            if(MdmConstant.OUT.equals(mdmMovementType.getIoFlag())){
                // 出库从明细获取项目
                projectId = StringUtils.isBlank(stockInOutDetail.getProjectId()) ? "" : stockInOutDetail.getProjectId();
            }
            String batchNo = StringUtils.isBlank(stockInOutDetail.getBatchNo()) ? "" : stockInOutDetail.getBatchNo();
            String locationId = StringUtils.isBlank(stockInOutDetail.getStorageLocationId()) ? "" : stockInOutDetail.getStorageLocationId();
            MmMaterialStock oldMaterialStock = mmMaterialStockMapper.selectMaterialStock(materialId, warehouseId, locationId, batchNo, projectId);
            BigDecimal orderDetailQty = stockInOutDetail.getQty() == null ? BigDecimal.ZERO : stockInOutDetail.getQty();
            if(MdmConstant.OUT.equals(mdmMovementType.getIoFlag()) && orderDetailQty.compareTo(BigDecimal.ZERO) == 1 && oldMaterialStock == null){
                throw new RuntimeException("未找到库存信息");
            }
            BigDecimal stockQty = oldMaterialStock == null ? BigDecimal.ZERO : oldMaterialStock.getStockQty();
            BigDecimal stockAvailableQty = oldMaterialStock == null ? BigDecimal.ZERO : oldMaterialStock.getStockQtyAvailable();
            BigDecimal stockAllocateQty = oldMaterialStock == null ? BigDecimal.ZERO : oldMaterialStock.getStockQtyAllocate();
            BigDecimal stockSumPrice = oldMaterialStock == null ? BigDecimal.ZERO : oldMaterialStock.getSumPrice();
            BigDecimal stockUnitPrice = oldMaterialStock == null ? BigDecimal.ZERO : oldMaterialStock.getUnitPrice();
            BigDecimal orderDetailSumPrice = stockInOutDetail.getSumPrice() == null ? BigDecimal.ZERO : stockInOutDetail.getSumPrice();
            BigDecimal resultQty = null;
            BigDecimal resultSumPrice = null;
            BigDecimal resultAvailebaleQty = null;
            BigDecimal resultAllocateQty = null;
            if (MdmConstant.IN.equals(mdmMovementType.getIoFlag())) {
                // 入库
                resultQty = stockQty.add(orderDetailQty);
                resultSumPrice = stockSumPrice.add(orderDetailSumPrice);
                resultAvailebaleQty = stockAvailableQty.add(orderDetailQty);
                resultAllocateQty = stockAllocateQty;
            } else {
                // 出库
                resultQty = stockQty.subtract(orderDetailQty);
                resultSumPrice = resultQty.multiply(stockUnitPrice).setScale(2, BigDecimal.ROUND_HALF_UP);
                if (isAllocate) {
                    // 已分配库存
                    resultAvailebaleQty = stockAvailableQty;
                    resultAllocateQty = stockAllocateQty.subtract(orderDetailQty);
                } else {
                    // 直接创建出库单，未分配库存
                    resultAvailebaleQty = stockAvailableQty.subtract(orderDetailQty);
                    resultAllocateQty = stockAllocateQty;
                }
            }
            if (resultQty.compareTo(BigDecimal.ZERO) == -1) {
                throw new RuntimeException("库存量不能小于零：" + stockInOutDetail.getMaterialNo());
            }
            if (resultAvailebaleQty.compareTo(BigDecimal.ZERO) == -1) {
                throw new RuntimeException("可用库存量不能小于零：" + stockInOutDetail.getMaterialNo());
            }
            if (resultAllocateQty.compareTo(BigDecimal.ZERO) == -1) {
                throw new RuntimeException("已分配量不能小于零：" + stockInOutDetail.getMaterialNo());
            }
            int count = 0;
            if (oldMaterialStock == null) {
                // 新增库存
                MmMaterialStock newMaterialStock = new MmMaterialStock();
                newMaterialStock.setMaterialId(materialId);
                newMaterialStock.setMaterialNo(stockInOutDetail.getMaterialNo());
                newMaterialStock.setMaterialDesc(stockInOutDetail.getMaterialDesc());
                newMaterialStock.setUnit(stockInOutDetail.getUnit());
                newMaterialStock.setWarehouseId(warehouseId);
                newMaterialStock.setStorageLocationId(locationId);
                newMaterialStock.setBatchNo(batchNo);
                newMaterialStock.setStockQty(resultQty);
                newMaterialStock.setUnitPrice(stockInOutDetail.getUnitPrice() == null ? BigDecimal.ZERO : stockInOutDetail.getUnitPrice());
                newMaterialStock.setSumPrice(resultSumPrice);
                newMaterialStock.setStockQtyAllocate(resultAllocateQty);
                newMaterialStock.setStockQtyAvailable(resultAvailebaleQty);
                newMaterialStock.setCreateBy(mmStockInOut.getCreateBy());
                newMaterialStock.setCreateTime(mmStockInOut.getCreateTime());
                newMaterialStock.setProjectId(projectId);
                newMaterialStock.setTenantId(mmStockInOut.getTenantId());
                count = baseMapper.insert(newMaterialStock);
            } else {
                // 修改库存
                MmMaterialStock modMaterialStock = new MmMaterialStock();
                modMaterialStock.setStockQty(resultQty);
                modMaterialStock.setStockQtyAvailable(resultAvailebaleQty);
                modMaterialStock.setStockQtyAllocate(resultAllocateQty);
                modMaterialStock.setSumPrice(resultSumPrice);
                if (resultQty.compareTo(BigDecimal.ZERO) != 0 && resultSumPrice.compareTo(BigDecimal.ZERO) != 0) {
                    modMaterialStock.setUnitPrice(resultSumPrice.divide(resultQty, 4, RoundingMode.HALF_UP));
                }
                modMaterialStock.setVersion(oldMaterialStock.getVersion() + 1);
                LambdaQueryWrapper<MmMaterialStock> queryWrapper = new LambdaQueryWrapper<>();
                queryWrapper.eq(MmMaterialStock::getId, oldMaterialStock.getId())
                        .eq(MmMaterialStock::getVersion, oldMaterialStock.getVersion());
                count = mmMaterialStockMapper.update(modMaterialStock, queryWrapper);
            }
            if (count <= 0) {
                throw new RuntimeException("数据已被更新，请重新操作");
            }
        }

        return true;
    }

    /**
     * 已分配量更新
     *
     * @param allocateModel
     * @return void
     * @throws
     */
    @Transactional
    @Override
    public void updateStockAllocate(MmMaterialStockAllocateModel allocateModel) throws Exception {
        String batchNo = allocateModel.getBatchNo() == null ? "" : allocateModel.getBatchNo();
        String projectId = allocateModel.getProjectId() == null ? "" : allocateModel.getProjectId();
        MmMaterialStock mmMaterialStock = mmMaterialStockMapper.selectMaterialStock(allocateModel.getMaterialId(), allocateModel.getWarehouseId(),
                allocateModel.getStorageLocationId(), batchNo, projectId);
        if (mmMaterialStock == null) {
            throw new RuntimeException("未找到库存信息，无法分配库存");
        }
        MmMaterialStock materialStockModify = new MmMaterialStock();
        materialStockModify.setId(mmMaterialStock.getId());
        materialStockModify.setVersion(mmMaterialStock.getVersion() + 1);
        BigDecimal oldAllocateQty = allocateModel.getOldQty().compareTo(BigDecimal.ZERO) == 1 ? allocateModel.getOldQty() : BigDecimal.ZERO;
        BigDecimal newAllocateQty = allocateModel.getNewQty().compareTo(BigDecimal.ZERO) == 1 ? allocateModel.getNewQty() : BigDecimal.ZERO;
        // 已分配量
        BigDecimal qtyAllocate = mmMaterialStock.getStockQtyAllocate().subtract(oldAllocateQty).add(newAllocateQty);
        if (qtyAllocate.compareTo(BigDecimal.ZERO) == -1) {
            throw new RuntimeException("库存分配量不能小于0");
        }
        materialStockModify.setStockQtyAllocate(qtyAllocate);
        // 可用库存
        BigDecimal qtyAvailable = mmMaterialStock.getStockQtyAvailable().add(oldAllocateQty).subtract(newAllocateQty);
        if (qtyAvailable.compareTo(BigDecimal.ZERO) == -1) {
            throw new RuntimeException("可用库存量不能小于0");
        }
        materialStockModify.setStockQtyAvailable(qtyAvailable);
        // 更新
        LambdaQueryWrapper<MmMaterialStock> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(MmMaterialStock::getId, mmMaterialStock.getId())
                .eq(MmMaterialStock::getVersion, mmMaterialStock.getVersion());
        int updCount = mmMaterialStockMapper.update(materialStockModify, queryWrapper);
        if (updCount <= 0) {
            throw new RuntimeException("数据已被更新，请重新操作");
        }
    }

    @Override
    public IPage<MmRptMaterialStockWarehouseStatModel> queryRptWarehouseStatList(Page<MmRptMaterialStockWarehouseStatModel> page, MmRptMaterialStockStatPage mmRptMaterialStockStatPage) {
        return page.setRecords(mmMaterialStockMapper.selectRptWarehouseStatList(page, mmRptMaterialStockStatPage));
    }

    @Override
    public MmRptMaterialStockWarehouseStatTotalModel queryRptWarehouseStatTotal(MmRptMaterialStockStatPage mmRptMaterialStockStatPage) {
        return mmMaterialStockMapper.selectRptWarehouseStatTotal(mmRptMaterialStockStatPage);
    }
}
